package com.atguigu.gmall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.execption.GmallException;
import com.atguigu.gmall.common.util.HttpClientUtil;
import com.atguigu.gmall.constant.MqConst;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.PaymentWay;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.order.mapper.OrderDetailMapper;
import com.atguigu.gmall.order.mapper.OrderInfoMapper;
import com.atguigu.gmall.order.service.OrderService;
import com.atguigu.gmall.service.RabbitService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.http.client.utils.HttpClientUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author mgx
 * @version 1.0
 * @description: TODO
 * @date 2022-12-10 13:51
 */
@Service
@SuppressWarnings("all")
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private RedisTemplate redisTemplate;


    @Value("${ware.url}")
    private String wareUrl;

    @Autowired
    private RabbitService rabbitService;

    /**
     * 提交订单 -- 下单
     * @param orderInfo
     * @return
     */
    @Override
    public Long submitOrder(OrderInfo orderInfo) {
        // 往订单信息中封装数据
        orderInfo.sumTotalAmount();
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        orderInfo.setPaymentWay(PaymentWay.ONLINE.name());
        String outTradeNo = "atguigu" + UUID.randomUUID().toString().replace("-", "");
        orderInfo.setOutTradeNo(outTradeNo);
        StringBuilder tradeBody = new StringBuilder();
        // 订单描述
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        for (OrderDetail orderDetail : orderDetailList) {
            tradeBody.append(orderDetail.getSkuName() + "   ");
        }
        if(tradeBody.toString().length() > 100) {
            orderInfo.setTradeBody(tradeBody.toString().substring(0,100));
        }else {
            orderInfo.setTradeBody(tradeBody.toString());
        }
        orderInfo.setOperateTime(new Date());
        // 过期时间设置为+1天
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, 1);
        orderInfo.setExpireTime(calendar.getTime());
        // 设置过程进度
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());

        // 保存订单信息
        orderInfoMapper.insert(orderInfo);

        // 保存订单明细
        for (OrderDetail orderDetail : orderDetailList) {
            orderDetail.setOrderId(orderInfo.getId());
            orderDetailMapper.insert(orderDetail);
        }

        // 发送延迟消息到MQ
        rabbitService.sendDelayMessage(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL,
                MqConst.ROUTING_ORDER_CANCEL, orderInfo.getId(), MqConst.DELAY_TIME);
        // 删除购物车清单
        //redisTemplate.delete(RedisConst.USER_KEY_PREFIX+userId+RedisConst.USER_CART_KEY_SUFFIX);
        return orderInfo.getId();
    }

    /**
     * 生成流水号
     * @param userId
     * @return
     */
    @Override
    public String getTradeNo(String userId) {
        String tradeNoKey = "user:" + userId + ":tradeNo";
        String value = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set(tradeNoKey, value);
        return value;
    }

    /**
     * 校验流水号
     * @param userId
     * @param tradeNo
     * @return
     */
    @Override
    public boolean checkTradeCode(String userId, String tradeNo) {
        // 从redis中取出
        String key = "user:" + userId + ":tradeNo";
        String value = (String) redisTemplate.opsForValue().get(key);
        // 判空一下
        if(StringUtils.isEmpty(value)) {
            return false;
        }

        return value.equals(tradeNo);
    }

    /**
     * 删除流水号
     * @param userId
     */
    @Override
    public void deleteTradeNo(String userId) {
        String key = "user:" + userId + ":tradeNo";
        redisTemplate.delete(key);
    }

    /**
     * 校验库存
     * @param skuId
     * @param skuNum
     * @return
     */
    @Override
    public boolean checkStock(Long skuId, Integer skuNum) {
        // 远程请求我们的库存系统，发出http请求
        // 远程请求路由：http://localhost:9001/hasStock?skuId=skuId&num=skuNum
        String result = HttpClientUtil.doGet(wareUrl + "/hasStock?skuId=" + skuId + "&num=" + skuNum);

        return "1".equals(result);
    }

    /**
     * 获取当前用户的我的订单
     * @param pageParam
     * @param userId
     * @return
     */
    @Override
    public IPage<OrderInfo> getPage(Page<OrderInfo> pageParam, String userId) {
        // 使用对应的mapper直接执行sql
        IPage<OrderInfo> orderInfoPage = orderInfoMapper.selectOrderInfoPageByUserId(pageParam, userId);
        orderInfoPage.getRecords().forEach(orderInfo -> {
            orderInfo.setOrderStatusName(OrderStatus.getStatusNameByStatus(orderInfo.getOrderStatus()));
        });
        return orderInfoPage;
    }

    /**
     * 关闭订单
     * @param orderId 订单id
     * @param flag 判断是否是需要通知关闭本地支付记录
     */
    @Override
    public void execExpiredOrder(Long orderId, String flag) {
        // 关闭订单
        this.updateOrderStatus(orderId, ProcessStatus.CLOSED);
        // TODO 发送消息取消支付记录
        if("2".equals(flag)) {
            this.rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,
                    MqConst.ROUTING_PAYMENT_CLOSE, orderId);
        }
    }


    /**
     * 根据订单Id 修改订单的状态
     * @param orderId
     * @param processStatus
     */
    @Override
    public void updateOrderStatus(Long orderId, ProcessStatus processStatus) {
        boolean update = lambdaUpdate()
                .eq(OrderInfo::getId, orderId)
                .set(OrderInfo::getOrderStatus, processStatus.getOrderStatus().name())
                .set(OrderInfo::getProcessStatus, processStatus.name())
                .update();

        if(!update) {
            throw new RuntimeException("更新订单状态失败");
        }
    }

    /**
     * 获取订单详情
     * @param orderId
     * @return
     */
    @Override
    public OrderInfo getOrderInfoById(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if(orderInfo != null) {
            LambdaQueryWrapper<OrderDetail> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(OrderDetail::getOrderId, orderId);
            List<OrderDetail> orderDetails = orderDetailMapper.selectList(wrapper);
            orderInfo.setOrderDetailList(orderDetails);
        }
        return orderInfo;
    }

    /**
     *  通知仓储扣减库存
     * @param orderId 订单id
     */
    @Override
    public void sendOrderStatus(Long orderId) {
        // 更新订单状态为NOTIFIED_WARE
        this.updateOrderStatus(orderId, ProcessStatus.NOTIFIED_WARE);

        // 初始化调用仓储服务的接口请求参数
        String wareJson = initWareOrder(orderId);

        // 发送消息给队列，通知仓储扣减库存
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_WARE_STOCK, MqConst.ROUTING_WARE_STOCK, wareJson);
    }

    private String initWareOrder(Long orderId) {
        // 查询订单信息
        OrderInfo orderInfo = getOrderInfoById(orderId);

        // 将orderInfo中部分数据转换为Map
        Map map = initWareOrder(orderInfo);


        return JSON.toJSONString(map);
    }


    private Map initWareOrder(OrderInfo orderInfo) {
        Map<String, Object> map = initWareOrderMap(orderInfo);

        return map;
    }

    @Override
    public Map<String, Object> initWareOrderMap(OrderInfo orderInfo) {
        Map<String, Object> map = new HashMap<>();
        map.put("orderId", orderInfo.getId());
        map.put("consignee", orderInfo.getConsignee());
        map.put("consigneeTel", orderInfo.getConsigneeTel());
        map.put("ordercomment", orderInfo.getOrderComment());
        map.put("orderBody", orderInfo.getTradeBody());
        map.put("deliveryAddress", orderInfo.getDeliveryAddress());
        map.put("paymentway", "2");
        map.put("wareId", orderInfo.getWareId());

        List<Map<String, Object>> orderDetailMaps = orderInfo.getOrderDetailList().stream().map(orderDetail -> {
            Map<String, Object> temp = new HashMap<>();
            temp.put("skuId", orderDetail.getSkuId());
            temp.put("skuNum", orderDetail.getSkuNum());
            temp.put("skuName", orderDetail.getSkuName());
            return temp;
        }).collect(Collectors.toList());
        map.put("details", orderDetailMaps);
        return map;
    }

    /**
     * 拆单
     * @param orderId 订单id
     * @param wareSkuMap 仓库与sku的对应关系
     *                   [{"wareId":"1","skuIds":["2","10"]},{"wareId":"2","skuIds":["3"]}]
     * @return 子订单集合
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<OrderInfo> orderSplit(String orderId, String wareSkuMap) {
        // 创建返回结果 -- 子订单集合
        List<OrderInfo> resultList = new ArrayList<>();
        // 转化仓储服务请求的参数
        List<Map> wareSkuList = JSON.parseArray(wareSkuMap, Map.class);
        // 查询原始订单
        OrderInfo orderInfoOrigin = getOrderInfoById(Long.parseLong(orderId));
        if(!CollectionUtils.isEmpty(wareSkuList)) {
            for (Map map : wareSkuList) {
                //{"wareId":"1","skuIds":["2","10"]}
                String wareId = (String) map.get("wareId");
                List<String> skuIds = (List<String>) map.get("skuIds");
                // 创建子订单
                OrderInfo subOrderInfo = new OrderInfo();
                BeanUtils.copyProperties(orderInfoOrigin, subOrderInfo);
                // 修改部分属性，避免冲突
                subOrderInfo.setId(null);
                subOrderInfo.setParentOrderId(Long.parseLong(orderId));
                subOrderInfo.setWareId(wareId);
                // 创建一个同在一个仓库的子订单集合
                List<OrderDetail> subOrderDetailList = new ArrayList<>();
                StringBuilder builder = new StringBuilder();
                // 获取父订单的订单详情
                List<OrderDetail> orderDetailList = orderInfoOrigin.getOrderDetailList();
                if (!CollectionUtils.isEmpty(orderDetailList) && orderDetailList.size() > 0) {
                    subOrderDetailList = orderDetailList.stream().filter(orderDetail
                            -> skuIds.contains(String.valueOf(orderDetail.getSkuId())))
                            .peek(orderDetail -> builder.append(orderDetail.getSkuName() + " "))
                            .collect(Collectors.toList());
                    subOrderInfo.setOrderDetailList(subOrderDetailList);
                }
                // 计算总金额
                subOrderInfo.sumTotalAmount();
                // 订单描述
                subOrderInfo.setTradeBody(builder.toString());
                // 保存到数据库
                this.submitOrder(subOrderInfo);
                // 添加到结果中
                resultList.add(subOrderInfo);
            }
            // 修改父订单状态为已拆单
            this.updateOrderStatus(Long.parseLong(orderId), ProcessStatus.SPLIT);
        }
        return resultList;
    }
}
